package com.xdcplus.web.service.bd.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageInfo;
import com.xdcplus.core.utils.BeanUtils;
import com.xdcplus.exceptions.XdcWebException;
import com.xdcplus.exceptions.domain.ResponseVO;
import com.xdcplus.mom.constants.NumberConstant;
import com.xdcplus.mom.enums.ResponseEnum;
import com.xdcplus.mom.utils.AuthUtils;
import com.xdcplus.mp.service.impl.BaseServiceImpl;
import com.xdcplus.mp.utils.PageableUtils;
import com.xdcplus.mp.utils.PropertyUtils;
import com.xdcplus.pager.vo.PageVO;
import com.xdcplus.system.api.UserInfoRemote;
import com.xdcplus.web.common.enums.FactoryRegionTypeEnum;
import com.xdcplus.web.common.pojo.dto.bd.BdFactoryDTO;
import com.xdcplus.web.common.pojo.dto.bd.BdFactoryFilterDTO;
import com.xdcplus.web.common.pojo.dto.tool.ToolInfoFilterDTO;
import com.xdcplus.web.common.pojo.entity.bd.BdFactory;
import com.xdcplus.web.common.pojo.query.bd.BdFactoryQuery;
import com.xdcplus.web.common.pojo.vo.bd.BdFactoryVO;
import com.xdcplus.web.mapper.bd.BdFactoryMapper;
import com.xdcplus.web.service.bd.BdFactoryService;
import com.xdcplus.web.service.tool.ToolInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 工厂模型表(BdFactory)表服务实现类
 *
 * @author Fish.Fei
 * @since 2023-01-31 13:35:21
 */
@Slf4j
@Service("bdFactoryService")
public class BdFactoryServiceImpl extends BaseServiceImpl<BdFactoryMapper, BdFactory, BdFactory, BdFactoryVO> implements BdFactoryService {

    @Autowired
    protected BdFactoryMapper bdFactoryMapper;

    @Autowired
    protected ToolInfoService toolInfoService;

    @Autowired
    protected UserInfoRemote userInfoRemote;

    /**
     * 默认顶多的根节点的父级ID
     */
    private Long defaultParentRootId=0L;

    /**
     * 检验区域Code是否存在
     * @param regionCode 区域Code
     * @param excludeId 排除的ID
     */
    private void checkRegionCodeIsExists(String regionCode,Long excludeId){
        BdFactory bdFactory =bdFactoryMapper.queryBdFactoryByRegionCode(regionCode);
        if(bdFactory==null || (excludeId!=null && bdFactory.getId().equals(excludeId))){
            return;
        }
        throw new XdcWebException(ResponseEnum.ERROR,"编码存在重复，请重新输入");

    }
    private void checkRegionNameIsExists(String regionName,Long excludeId){
        BdFactory bdFactory =bdFactoryMapper.queryBdFactoryByRegionName(regionName);
        if(bdFactory==null || (excludeId!=null && bdFactory.getId().equals(excludeId))){
            return;
        }
        throw new XdcWebException(ResponseEnum.ERROR,"名称存在重复，请重新输入");

    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean saveBdFactory(BdFactoryDTO bdFactoryDTO) {
        BdFactory bdFactory = new BdFactory();
        //检查区域Code是否已经存在
        checkRegionCodeIsExists(bdFactoryDTO.getRegionCode(),null);
        checkRegionNameIsExists(bdFactoryDTO.getRegionName(),null);
        BeanUtil.copyProperties(bdFactoryDTO, bdFactory);
        if(bdFactory.getParentId()==null){
            bdFactory.setParentId(defaultParentRootId);
        }
        bdFactory.setCreatedTime(new Timestamp(DateUtil.current()));

        return this.save(bdFactory);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean updateBdFactory(BdFactoryDTO bdFactoryDTO) {

        BdFactory bdFactory = this.getById(bdFactoryDTO.getId());
        if (ObjectUtil.isNull(bdFactory)) {
            log.error("updateBdFactory() The BdFactory does not exist or has been deleted");
            throw new XdcWebException(ResponseEnum.ERROR);
        }
        //检查区域Code是否已经存在
        checkRegionCodeIsExists(bdFactoryDTO.getRegionCode(),bdFactoryDTO.getId());
        checkRegionNameIsExists(bdFactoryDTO.getRegionName(),bdFactoryDTO.getId());
        BeanUtil.copyProperties(bdFactoryDTO, bdFactory);
        bdFactory.setUpdatedUser(bdFactoryDTO.getUpdatedUser());
        bdFactory.setUpdatedTime(new Timestamp(DateUtil.current()));

        return this.updateById(bdFactory);
    }

    @Override
    public Boolean saveOrUpdateBatch(List<BdFactory> bdFactoryList) {
        bdFactoryList.forEach(bdFactory -> {
            BdFactory bdFactoryParam = new BdFactory();
            bdFactoryParam.setId(bdFactory.getId());
            if (ObjectUtil.isNotNull(bdFactory.getId())) {
                bdFactory.setId(bdFactory.getId());
                bdFactory.setUpdatedTime(new Timestamp(DateUtil.current()));
                LambdaUpdateWrapper<BdFactory> lambdaUpdate = Wrappers.lambdaUpdate();
                lambdaUpdate.eq(BdFactory::getId, bdFactory.getId());
                update(bdFactory, lambdaUpdate);
            } else {
                bdFactory.setCreatedTime(new Timestamp(DateUtil.current()));
                save(bdFactory);
            }
        });
        return true;
    }

    @Override
    public Boolean saveOrUpdateBatchByDTOList(List<BdFactoryDTO> bdFactoryDTOList) {

        List<BdFactory> bdFactoryList = BeanUtils.copyProperties(bdFactoryDTOList, BdFactory.class);
        return saveOrUpdateBatch(bdFactoryList);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean deleteBdFactoryLogical(Long id) {

        Assert.notNull(id, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());

        BdFactory bdFactory = this.getById(id);

        if (ObjectUtil.isNull(bdFactory)) {
            log.error("deleteBdFactory() The BdFactory does not exist or has been deleted");
            throw new XdcWebException(ResponseEnum.ERROR);
        }
        return this.removeById(id);
    }
    
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean deleteBdFactoryByIds(String ids) {
        Assert.notNull(ids, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());
		List<String> idList = Arrays.asList(ids.split(","));
		if(CollectionUtil.isEmpty(idList)){
           throw new XdcWebException(ResponseEnum.ERROR);
       }
		idList.forEach(id->{
			BdFactory bdFactory = this.getById(id);
			if (ObjectUtil.isNull(bdFactory)) {
				log.error("deleteBdFactory() The BdFactory does not exist or has been deleted");
				throw new XdcWebException(ResponseEnum.ERROR);
			}
		});
		
        return this.removeByIds(idList);
    }

    @Override
    public Boolean deleteBdFactoryByIds(List<Long> ids) {
        Assert.notEmpty(ids, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());

        return this.removeByIds(ids);
    }

    private List<BdFactory> queryBdFactoryList(BdFactoryFilterDTO bdFactoryFilterDTO) {
        BdFactoryQuery bdFactoryQuery = BeanUtil.copyProperties(bdFactoryFilterDTO, BdFactoryQuery.class);
        ResponseVO<Set<Long>> setResponseVO = userInfoRemote.queryFactoryIdsByUserId(AuthUtils.getCurrentUserId());
        if (ObjectUtil.isNotNull(setResponseVO)) {
            bdFactoryQuery.setFactoryIds(new ArrayList<>(setResponseVO.getData()));
        }
        return bdFactoryMapper.queryBdFactory(bdFactoryQuery);
    }

    @Override
    public List<BdFactoryVO> queryBdFactoryVOList(BdFactoryFilterDTO bdFactoryFilterDTO) {
        return this.objectConversion(queryBdFactoryList(bdFactoryFilterDTO));
    }

    @Override
    public PageVO<BdFactoryVO> queryBdFactory(BdFactoryFilterDTO bdFactoryFilterDTO) {
        PageVO<BdFactoryVO> pageVO = new PageVO<>();

        if (bdFactoryFilterDTO.getCurrentPage() > NumberConstant.ZERO) {
            PageableUtils.basicPage(bdFactoryFilterDTO.getCurrentPage(), bdFactoryFilterDTO.getPageSize(),
                    bdFactoryFilterDTO.getOrderType(), bdFactoryFilterDTO.getOrderField());
        }

        List<BdFactory> bdFactoryList = queryBdFactoryList(bdFactoryFilterDTO);

        PageInfo<BdFactory> pageInfo = new PageInfo<>(bdFactoryList);
        PropertyUtils.copyProperties(pageInfo, pageVO, this.objectConversion(bdFactoryList));

        return pageVO;
    }

    @Override
    public BdFactoryVO queryBdFactoryById(Long id) {

        Assert.notNull(id, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());

        return this.objectConversion(this.getById(id));
    }

    @Override
    public List<BdFactoryVO> queryBdFactoryVOByParentId(Long parentId) {
        Assert.notNull(parentId, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());
        ResponseVO<Set<Long>> setResponseVO = userInfoRemote.queryFactoryIdsByUserId(AuthUtils.getCurrentUserId());
        return this.objectConversion(bdFactoryMapper.queryBdFactoryVOByParentId(parentId,new ArrayList<>(setResponseVO.getData())));
    }


    @Override
    public List<BdFactoryVO> queryBdFactoryVOTree(Long parentId) {
        Assert.notNull(parentId, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());
        List<BdFactoryVO> bdFactoryVOS = CollectionUtil.newArrayList();

        if (Validator.equal(defaultParentRootId, parentId)) {
            bdFactoryVOS.addAll(this.objectConversionWithToolInfo(queryBdFactoryList(new BdFactoryFilterDTO())));
        }else {
            getBdFactoryVOByParentId(bdFactoryVOS,parentId);
        }
        return toTree(bdFactoryVOS, parentId);
    }

    @Override
    public List<BdFactoryVO> getWorkshopProductionLineTree() {
        List<BdFactoryVO> bdFactoryVOS = CollectionUtil.newArrayList();
        ResponseVO<Set<Long>> setResponseVO = userInfoRemote.queryFactoryIdsByUserId(AuthUtils.getCurrentUserId());
        List<BdFactory>  BdFactoryList= bdFactoryMapper.queryBdFactoryVOByParentId(defaultParentRootId,
                new ArrayList<>(setResponseVO.getData()));
        List<BdFactoryVO> result=new ArrayList<>();
        if(CollectionUtil.isNotEmpty(BdFactoryList)){
            for(BdFactory bFactory:BdFactoryList) {
                getBdFactoryVOByParentId(bdFactoryVOS, bFactory.getId());
                result.addAll(toTree(bdFactoryVOS, bFactory.getId()));
            }
        }
        return result;
    }

    @Override
    public Boolean deleteBdFactoryWithChildren(Long id) {
        List<Long> ids =CollectionUtil.newArrayList();
        ids.add(id);
        getIds(ids,id);

        return deleteBdFactoryByIds(ids);
    }

    @Override
    public List<BdFactoryVO> queryBdFactoryVOWithOpeTree() {
        return null;
    }

    @Override
    public BdFactoryVO queryBdFactoryByCode(String code) {

        return this.objectConversion(bdFactoryMapper.selectOne(new QueryWrapper<BdFactory>().eq("REGION_CODE",code)));
    }

    @Override
    public List<BdFactory> queryBdFactoryByCodeIn(List<String> codeList) {
        return null;
    }


    @Override
    public List<BdFactory> queryBdFactoryByIds(List<Long> ids) {

        return bdFactoryMapper.selectList(new QueryWrapper<BdFactory>().in("ID",ids));
    }


    @Override
    public BdFactoryVO objectConversion(BdFactory s) {
        BdFactoryVO bdFactoryVO = super.objectConversion(s);
        if(!Validator.equal(bdFactoryVO.getParentId(),NumberConstant.ZERO.longValue())){
            bdFactoryVO.setParentName(queryBdFactoryById(bdFactoryVO.getParentId()).getRegionName());
        }

        return bdFactoryVO;
    }

    @Override
    public List<BdFactoryVO> objectConversion(List<BdFactory> sList) {
        if (!CollectionUtil.isNotEmpty(sList)) {
            return null;
        } else {
            List<BdFactoryVO> tList = new ArrayList();
            Iterator var3 = sList.iterator();

            while (var3.hasNext()) {
                BdFactory s = (BdFactory) var3.next();
                BdFactoryVO t = this.objectConversion(s);
                Optional.ofNullable(t).ifPresent(tList::add);
            }

            return tList;
        }
    }

    private void getBdFactoryVOByParentId(List<BdFactoryVO> bdFactoryVOS, Long parentId) {
        List<BdFactoryVO> bdFactoryVOList = this.queryBdFactoryVOByParentId(parentId);
        if (CollectionUtil.isNotEmpty(bdFactoryVOList)) {
            bdFactoryVOS.addAll(bdFactoryVOList);
            for (BdFactoryVO bdFactoryVO : bdFactoryVOList) {
                getBdFactoryVOByParentId(bdFactoryVOS, bdFactoryVO.getId());
            }
        }
    }

    /**
     * 转树结构
     *
     */
    private List<BdFactoryVO> toTree(List<BdFactoryVO> bdFactoryVOList, Long parentId) {
        if (CollectionUtil.isNotEmpty(bdFactoryVOList)) {
            List<BdFactoryVO> bdFactoryVOS = bdFactoryVOList.stream().filter(a -> Validator.equal(a.getParentId(), parentId)).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(bdFactoryVOS)){
                for (BdFactoryVO bdFactoryVO : bdFactoryVOS) {
                    List<BdFactoryVO> bdFactoryVOSChildren = toTree(bdFactoryVOList, bdFactoryVO.getId());
                    if(CollectionUtil.isNotEmpty(bdFactoryVOSChildren)){
                        bdFactoryVO.setChildren(bdFactoryVOSChildren);
                    }
                }
            }
            return bdFactoryVOS;
        }
        return Collections.emptyList();
    }


    //递归方法
    private void getIds(List<Long> ids, Long id) {
        //查询二级分类的对象
        List<BdFactory> bdFactorys = bdFactoryMapper.selectList(new QueryWrapper<BdFactory>().eq("parent_id",id));

        //遍历二级分类的对象，把二级分类的id加入到要删除的集合中
        for (BdFactory bdFactory : bdFactorys) {
            Long childrenId = bdFactory.getId();
            ids.add(childrenId);
            //把二级分类的每一个ID，查询它下面的子节点
            this.getIds(ids,childrenId);
        }
    }

    public BdFactoryVO objectConversionWithToolInfo(BdFactory s) {
        BdFactoryVO bdFactoryVO = super.objectConversion(s);
        if(ObjectUtil.isNotEmpty(bdFactoryVO) && Validator.equal(bdFactoryVO.getRegionType(), FactoryRegionTypeEnum.REGION.getCode())){
            ToolInfoFilterDTO toolInfoFilterDTO = new ToolInfoFilterDTO();
            toolInfoFilterDTO.setFactoryIdFk(bdFactoryVO.getId());
            bdFactoryVO.setToolInfoVOS(toolInfoService.queryToolInfoVOList(toolInfoFilterDTO));
        }

        return bdFactoryVO;
    }

    public List<BdFactoryVO> objectConversionWithToolInfo(List<BdFactory> sList) {
        if (!CollectionUtil.isNotEmpty(sList)) {
            return null;
        } else {
            List<BdFactoryVO> tList = new ArrayList();
            Iterator var3 = sList.iterator();

            while(var3.hasNext()) {
                BdFactory s = (BdFactory)var3.next();
                BdFactoryVO t = this.objectConversion(s);
                Optional.ofNullable(t).ifPresent(tList::add);
            }

            return tList;
        }
    }
}
